package la.iok.hzsvn.lewin.movie.controller;

import la.iok.hzsvn.lewin.movie.config.RedisKey;
import la.iok.hzsvn.lewin.movie.core.RoleEnum;
import la.iok.hzsvn.lewin.movie.core.Token;
import la.iok.hzsvn.lewin.movie.core.exception.ErrorCode;
import la.iok.hzsvn.lewin.movie.core.model.MovieVo;
import la.iok.hzsvn.lewin.movie.core.movieservice.param.MovieVersionListParam;
import la.iok.hzsvn.lewin.movie.entity.Movie;
import la.iok.hzsvn.lewin.movie.entity.MovieInstance;
import la.iok.hzsvn.lewin.movie.model.MovieDeleteContext;
import la.iok.hzsvn.lewin.movie.model.PublishParam;
import la.iok.hzsvn.lewin.movie.service.*;
import la.iok.hzsvn.lewin.mybatis.model.PageParam;
import la.iok.hzsvn.lewin.mybatis.model.PageVo;
import la.iok.hzsvn.lewin.mybatis.model.SortParam;
import la.iok.hzsvn.redis.model.ProgressKey;
import la.iok.hzsvn.redis.model.TaskProgress;
import la.iok.hzsvn.redis.service.ProgressTaskService;
import la.iok.hzsvn.share.annotations.Nullable;
import la.iok.hzsvn.share.response.OperatorResponse;
import la.iok.hzsvn.share.response.OperatorResponses;
import la.iok.hzsvn.share.response.SingleDataResponse;
import la.iok.hzsvn.share.tools.exception.SystemException;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.web.bind.annotation.*;

import javax.servlet.http.HttpServletResponse;
import java.util.UUID;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;

@RestController
@RequestMapping("movieInstances")
public class MovieInstanceController {
    private static final Logger logger = LoggerFactory.getLogger(MovieInstanceController.class);
    private final MovieInstanceService movieInstanceService;
    private final ExecutorService executorService = Executors.newFixedThreadPool(2*Runtime.getRuntime().availableProcessors());
    private final ProgressTaskService progressTaskService;
    private final RedisKey redisKey;
    private final MovieCoverFileService movieCoverFileService;
    private final MovieAssistFileService movieAssistFileService;
    private final MovieService movieService;
    private final MovieDownloadService movieDownloadService;
    private final DeviceLocalMovieService deviceLocalMovieService;

    public MovieInstanceController(MovieInstanceService movieInstanceService,
                                   ProgressTaskService progressTaskService,
                                   RedisKey redisKey,
                                   MovieCoverFileService movieCoverFileService,
                                   MovieAssistFileService movieAssistFileService,
                                   MovieService movieService,
                                   MovieDownloadService movieDownloadService,
                                   DeviceLocalMovieService deviceLocalMovieService) {
        this.movieInstanceService = movieInstanceService;
        this.progressTaskService = progressTaskService;
        this.redisKey = redisKey;
        this.movieCoverFileService = movieCoverFileService;
        this.movieAssistFileService = movieAssistFileService;
        this.movieService = movieService;
        this.movieDownloadService = movieDownloadService;
        this.deviceLocalMovieService = deviceLocalMovieService;
    }

    /**
     * 发布剧本
     * @param token 操作用户
     * @param id 剧本id
     * @param param 发布参数
     * @return 新发布的剧本实例id
     */
    @PostMapping("movie/{id}")
    public SingleDataResponse<ProgressKey> save(@RequestHeader Token token, @PathVariable Long id, @RequestBody PublishParam param){
        ProgressKey progressKey = new ProgressKey(redisKey.progressTaskKey(UUID.randomUUID().toString()));
        executorService.submit(()->{
            try{
                TaskProgress taskProgress = new TaskProgress(progressKey.getKey(),TaskProgress.STATUS_IN_PROGRESS);
                progressTaskService.startTask(taskProgress);
                movieInstanceService.publish(token,id,param,progressKey);
                progressTaskService.success(progressKey.getKey());
            }catch (SystemException e){
                logger.info("发布剧本{}失败",id,e);
                progressTaskService.failed(progressKey.getKey(),e.getMessage());
            }catch (Throwable e){
                logger.error("发布剧本{}失败",id,e);
                progressTaskService.failed(progressKey.getKey(),"发布剧本失败");
            }
        });
        return new SingleDataResponse<>(progressKey);
    }
    @GetMapping("task/{key}")
    public SingleDataResponse<TaskProgress> progress(@PathVariable String key){
        return new SingleDataResponse<>(progressTaskService.getProgress(key));
    }

    @GetMapping("executorInfo")
    public String executorInfo(@RequestHeader Token token){
        token.validAnyAuthority(RoleEnum.Admin);
        return executorService.toString();
    }

    @GetMapping
    public SingleDataResponse<PageVo<MovieVo>> page(
            @RequestHeader(required = false) Token token, @RequestParam(required = false) String orderColumn,
            @RequestParam(required = false) String order, int page, int limit, @Nullable String name,
            @Nullable String author, @Nullable String tag, @Nullable Integer minPlayers, @Nullable Integer maxPlayers,
            @Nullable Integer minDuration, @Nullable Integer maxDuration, Long movieLevelId,Integer excludeLocal,String deviceCode){
        return new SingleDataResponse<>(movieInstanceService.page(token,page,limit,orderColumn,order,name,author,tag,
                minPlayers,maxPlayers,minDuration,maxDuration,movieLevelId,excludeLocal,deviceCode));
    }

    /**
     * 剧本版本列表查询
     * @param token 操作用户
     * @param sortParam 排序规则
     * @param pageParam 分页参数
     * @param listParam 列表过滤参数
     * @return 分页对象
     */
    @GetMapping("versions")
    public SingleDataResponse<PageVo<MovieVo>> versions(
            @RequestHeader Token token, SortParam sortParam, PageParam pageParam, MovieVersionListParam listParam){
        return new SingleDataResponse<>(movieInstanceService.versions(token,pageParam,sortParam,listParam));
    }

    @GetMapping("movie/{id}")
    public SingleDataResponse<MovieVo> movieDetail(@RequestHeader Token token, @PathVariable Long id,@RequestParam(required = false) String deviceCode){
        return new SingleDataResponse<>(movieInstanceService.po2vo(movieInstanceService.movieDetail(token,id,deviceCode)));
    }

    @GetMapping("movie/{id}/v/{version}")
    public SingleDataResponse<MovieVo> movieDetail2(@RequestHeader Token token,@PathVariable Long id,
                                                    @PathVariable String version,@RequestParam(required = false) String deviceCode){
        return new SingleDataResponse<>(movieInstanceService.po2vo(movieInstanceService.movieDetail(token,id,version,deviceCode)));
    }

    /**
     * 下载剧本封面
     * @param token 操作用户
     * @param response 响应对象
     * @param id 剧本id
     */
    @GetMapping("movie/{id}/cover")
    public void downloadCover(@RequestHeader Token token, HttpServletResponse response, @PathVariable Long id){
        MovieInstance mi;
        if(token.getUserId() != null){
            //是用户请求,那返回最新的实例对应的图片
            mi = movieInstanceService.mostRecent(id);
        }else{
            //设备请求,那就是下载
             mi = movieInstanceService.select(movieDownloadService.loadDownloadInstance(token,id));
        }
        ErrorCode.MOVIE_INSTANCE_NOT_EXIST.assertNotNull(mi,()->{
            Movie m = movieService.select(id);
            return m == null?new Object[]{id}:new Object[]{m.getName()};
        });
        movieCoverFileService.downloadFile(response,mi.getCoverFileId(),mi.getName());
    }

    /**
     * 下载剧本封面
     * @param response 响应对象
     * @param id 剧本id
     */
    @GetMapping("movie/{id}/v/{version}/cover")
    public void downloadCover2(HttpServletResponse response, @PathVariable Long id, @PathVariable String version){
        MovieInstance mi = movieInstanceService.movieInst2(id,version);
        movieCoverFileService.downloadFile(response,mi.getCoverFileId(),mi.getName());
    }

    /**
     * 获取封面图的文件摘要
     * @param token 操作用户
     * @param id 剧本id
     * @return 文件摘要
     */
    @GetMapping("movie/{id}/cover/digest")
    public SingleDataResponse<String> coverDigest(@RequestHeader Token token,@PathVariable Long id){
        MovieInstance mi = movieInstanceService.select(movieDownloadService.loadDownloadInstance(token,id));
        ErrorCode.MOVIE_INSTANCE_NOT_EXIST.assertNotNull(mi,()->{
            Movie m = movieService.select(id);
            return m == null?new Object[]{id}:new Object[]{m.getName()};
        });
        SingleDataResponse<String> res = new SingleDataResponse<>();
        res.setData(movieCoverFileService.digest(mi.getCoverFileId()));
        return res;
    }

    /**
     * 获取封面图的文件摘要
     * @param id 剧本id
     * @return 文件摘要
     */
    @GetMapping("movie/{id}/v/{version}/cover/digest")
    public SingleDataResponse<String> coverDigest2(@PathVariable Long id, @PathVariable String version){
        MovieInstance mi = movieInstanceService.movieInst2(id,version);
        SingleDataResponse<String> res = new SingleDataResponse<>();
        res.setData(movieCoverFileService.digest(mi.getCoverFileId()));
        return res;
    }

    /**
     * 获取封面图的存储路径
     * @param id 剧本id
     * @return 文件摘要
     */
    @GetMapping("movie/{id}/v/{version}/cover/storePath")
    public SingleDataResponse<String> coverStorePath(@PathVariable Long id, @PathVariable String version){
        MovieInstance mi = movieInstanceService.movieInst2(id,version);
        SingleDataResponse<String> res = new SingleDataResponse<>();
        res.setData(movieCoverFileService.storePath(mi.getCoverFileId()));
        return res;
    }

    @GetMapping("total")
    public SingleDataResponse<Integer> total(@RequestHeader Token token){
        if(token.hasAuthority(RoleEnum.Admin)){
            return new SingleDataResponse<>(movieInstanceService.count(null));
        }else{
            return new SingleDataResponse<>(movieInstanceService.count(Movie.STATUS_ONLINE));
        }
    }
    @PostMapping("local")
    public OperatorResponse local(@RequestHeader Token token, @RequestBody Long[] movieIds){
        deviceLocalMovieService.updateMovieList(token,movieIds);
        return OperatorResponses.success();
    }

    @DeleteMapping("movie/{movieId}/v/{version}")
    public OperatorResponse deleteMovie(@RequestHeader Token token, @PathVariable Long movieId, @PathVariable String version,Integer deleteMovie){
        MovieDeleteContext ctx = movieInstanceService.deleteMovieFiles(token, movieId, version);
        movieInstanceService.cleanMovieFile(ctx);
        if(deleteMovie != null && deleteMovie == 1){
            movieInstanceService.delete(token,movieId,version);
        }
        return OperatorResponses.success();
    }

    @DeleteMapping("{id}/files")
    public OperatorResponse deleteMovieFiles(@RequestHeader Token token, @PathVariable Long id){
        MovieDeleteContext ctx = movieInstanceService.deleteMovieFiles(token, id);
        movieInstanceService.cleanMovieFile(ctx);
        return OperatorResponses.success();
    }

    @DeleteMapping("{id}")
    public OperatorResponse deleteMovie(@RequestHeader Token token, @PathVariable Long id){
        movieInstanceService.delete(token, id);
        return OperatorResponses.success();
    }

    /**
     * 下载剧本手册的html文件
     * @param response 响应对象
     * @param id 剧本id
     * @param version 剧本版本
     */
    @GetMapping("movie/{id}/v/{version}/assist/html/file")
    public void downloadAssist(HttpServletResponse response, @PathVariable Long id, @PathVariable String version){
        MovieInstance mi = movieInstanceService.movieInst2(id,version);
        movieAssistFileService.downloadFile(response,mi.getAssistHtmlFileId(),mi.getName());
    }

    /**
     * 获取封面图的文件摘要
     * @param id 剧本id
     * @return 文件摘要
     */
    @GetMapping("movie/{id}/v/{version}/assist/html/digest")
    public SingleDataResponse<String> assistDigest(@PathVariable Long id, @PathVariable String version){
        MovieInstance mi = movieInstanceService.movieInst2(id,version);
        return OperatorResponses.stringSingleDataResponse(movieAssistFileService.digest(mi.getAssistHtmlFileId()));
    }

    /**
     * 获取封面图的存储路径
     * @param id 剧本id
     * @return 文件摘要
     */
    @GetMapping("movie/{id}/v/{version}/assist/html/storePath")
    public SingleDataResponse<String> assistStorePath(@PathVariable Long id, @PathVariable String version){
        MovieInstance mi = movieInstanceService.movieInst2(id,version);
        return OperatorResponses.stringSingleDataResponse(movieAssistFileService.storePath(mi.getAssistHtmlFileId()));
    }
}
